/* 接收端 解压zip压缩包 功能 */

const compressing = require('compressing')
const fs = require('fs')
const { join, resolve } = require('path')
const {
  delDir,
  getFilesListByDir,
  mkdirs,
  sleep,
  log,
  succeed,
  error,
  underline
} = require('./index.js')


async function SaveFile(ctx, next) {
  const file = ctx.request.files.uploadname
  const filePath = join(ctx.app_config.uploadDir, file.name)
  const reader = fs.createReadStream(file.path)
  const writer = fs.createWriteStream(filePath)
  reader.pipe(writer)
  await next()
}


async function zip_files(
  filesList = [{ path: '', name: '' }],
  onClose = (zipObj) => {},
  zipName = 'files.zip'
) {
  const zipStream = fs.createWriteStream(zipName)
  const zip = archiver('zip')

  zipStream.on('close', function () {
    onClose(zip)
    // console.log('archiver has been finalized and the output file descriptor has closed.');
  })

  zipStream.on('end', function () {
    console.log('Data has been drained')
  })

  // zip错误事件
  zip.on('error', function (err) {
    throw err
  })
  zip.pipe(zipStream)

  log('正在往压缩包添加文件...')
  filesList.forEach((item) => {
    // 添加单个文件到压缩包
    zip.append(fs.createReadStream(item.path), { name: item.name })
  })
  log('文件添加完成！正在关闭zip压缩包文件...')

  await zip.finalize()
}

/* 中间件 清空resolve 接收文件夹 */
function clearResolveDir(config) {
	log("正在执行clearResolveDir中间件");
  return async (ctx, next) => {
    log('-----------------------------------------')

    if (!fs.existsSync(config.uploadDir)) {
      mkdirs(resolve(config.uploadDir, ''))
      log('清空上传缓存文件夹时发现没有此文件夹，已创建！')
    } else {
      log('正在清空uploadtemp文件夹')
      delDir(config.uploadDir, false)
      log('已清空uploadtemp文件夹')
    }
    await next()
  }
}

/**
 *接收文件之后，执行解压的中间件
 *
 * @param {*}
 */
async function compressing_zip(ctx, next) {
	log("正在执行compressing_zip中间件");
  log('接收成功，正在解压和部署...')
  await next()
  const zipPath = ctx.request.files.uploadname.filepath
  await sleep(300)
  // 解压缩
  await compressing.zip
    .uncompress(zipPath, ctx.app_config.deploy_dir)
    .then(async () => {
      log('解压到目标完成！')
      if (ctx.request.body.is_first == '0') {
        clearDeployedNotCover(ctx.app_config)
        log('清除不能覆盖的文件完成！')
        await compressTempNotCover(
          ctx.app_config,
          ctx.app_config.backupNotTempName
        )
        log('还原不能覆盖的文件完成！')
      }
    })
    .catch((err) => {
      log('解压出错：', err)

      throw new Error(msg)
    })
  succeed('部署成功！')
}

/* 清除旧文件的中间件 */
async function clearOldFile(ctx, next) {
	log("正在执行clearOldFile中间件");
  // log(ctx.request.body.is_first)
  if (ctx.request.body.is_first == '1') {
    ctx.app_config.backupNotTempName = await do_clearOldFiles(
      ctx.app_config,
      'all'
    )
  } else {
    ctx.app_config.backupNotTempName = await do_clearOldFiles(ctx.app_config)
  }
  await next()
}

/** 发布一个latest在其他文件夹中 */
async function copyZipToLatest(ctx, next) {
	log("正在执行copyZipToLatest中间件");
  await sleep(300)
  console.log(ctx.request.files)
  const zipPath = ctx.request.files.uploadname.filepath
  const latest_path =
    ctx.app_config.latest_dir + '/' + ctx.app_config.name + '.zip'
  fs.writeFileSync(latest_path, fs.readFileSync(zipPath))
  await next()
}
/**
 *执行，清空旧文件，
 *
 * @param {object} config koa提供的，要操作的目录等相关配置。
 * @param {boolean} [is_clear_all=false]
 * @returns
 */
async function do_clearOldFiles(config = {}, is_clear_all = false) {
	log("正在执行do_clearOldFiles中间件");
  log('正在处理旧文件...')
  const dirPath = config.deploy_dir
  const notCover = config.not_cover
  await saveOldAll(config)
  await sleep(300)

  /* 如果是初次部署，不需要再解压回notCover临时打包的文件 */
  if (is_clear_all) {
    files.delDir(dirPath, false)
    log('旧文件删除完成！')
    return
  }

  // 缓存不覆盖的旧文件
  const tempNotCoverZipName = await tempSaveNotCover(config)
  // log(tempNotCoverZipName)
  // 缓存好之后，执行清空部署目标目录
  files.delDir(dirPath, false)
  return tempNotCoverZipName
}

/* 临时将不能覆盖的文件列表压缩包并存起来 */
async function tempSaveNotCover(config = {}) {
  if (!fs.existsSync(config.not_cover_temp_path)) {
    mkdirs(resolve(config.not_cover_temp_path, ''))
  }
  delDir(config.not_cover_temp_path, false)
  const zip_list = []
  config.not_cover.forEach((item) => {
    const path = join(config.deploy_dir, item)
    if (fs.existsSync(path)) {
      const stat = fs.statSync(path)
      if (stat.isDirectory()) {
        getFilesListByDir(path).forEach((item2) => {
          zip_list.push({
            path: item2,
            name: item2.replace(join(config.deploy_dir, ''), '')
          })
        })
      } else if (stat.isFile()) {
        zip_list.push({
          path,
          name: item
        })
      }
    }
  })

  if (zip_list.length < 1) return

  const onClose = (zipObj) => {
    log(zipObj.pointer() + ' total bytes')
  }
  // 压缩包文件的名称path定义
  const zipName = join(
    config.not_cover_temp_path,
    `/not_cover__${formatDate(new Date(), 'yyyy_MM_dd__hh_mm_ss')}__${
      config.name
    }.zip`
  )
  // log(zip_list)
  await zip_files(zip_list, onClose, zipName).then((res) => {
    log('旧文件不覆盖列表已缓存')
  })
  return zipName
}

/* 将旧的完整项目文件夹保存一份在服务器，zip的 */
async function saveOldAll(config = {}) {
  log('旧文件开始备份！')
  let filesList = getFilesListByDir(config.deploy_dir)
  filesList = filesList.map((item) => {
    return {
      path: item,
      name: item.replace(join(config.deploy_dir, ''), '')
    }
  })
  const onClose = (zipObj) => {
    log(zipObj.pointer() + ' total bytes')
    log('旧文件整个备份完成！')
  }
  if (!fs.existsSync(config.history_path)) {
    mkdirs(resolve(config.history_path, ''))
  }
  const zipName = join(
    config.history_path,
    `/${config.name}__${formatDate(new Date(), 'yyyy_MM_dd__hh_mm_ss')}.zip`
  )
  // log(zipName)
  await zip_files(filesList, onClose, zipName)
}

/**  上传的文件解压之后，要尝试删除不能覆盖的配置的文件，怕前端将不能覆盖的文件还是传上来了 */
function clearDeployedNotCover(config = {}) {
  config.not_cover.forEach((item) => {
    const path = join(config.deploy_dir, item)
    if (fs.existsSync(path)) {
      const stat = fs.statSync(path)
      if (stat.isDirectory()) {
        delDir(path)
      } else if (stat.isFile()) {
        fs.unlinkSync(path)
      }
    }
  })
  return true
}

/** 解压临时备份的not_cover的文件进部署目标目录 */
async function compressTempNotCover(config, tempPath) {
  if (fs.existsSync(tempPath)) {
    await compressing.zip
      .uncompress(tempPath, config.deploy_dir)
      .then((res) => {
        log('备份的not cover文件还原成功！')
      })
      .catch((error) => {
        log('备份的not cover还原失败！')
      })
  } else {
    log('没有临时备份的not cover文件')
  }
  return true
}

/**
 *根据配置，从list里移除不能删除的文件和文件夹
 *
 * @param {string} [filePath=""]
 * @returns
 */
function isHave(config, filePath = '') {
  return config.not_cover.some((item) => {
    const path = join(config.deploy_dir, item)
    // console.log(path);
    // console.log(filePath);
    return filePath.indexOf(path) >= 0
  })
}

module.exports = {
  clearResolveDir,
  clearOldFile,
  compressing_zip,
  copyZipToLatest
}
